package com.lew.scott.happy.birthday;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Typeface;
import android.graphics.Paint.FontMetrics;
import android.graphics.PorterDuff.Mode;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.GestureDetector.OnGestureListener;

public class HappyBirthdayView extends SurfaceView implements SurfaceHolder.Callback, OnGestureListener {

	private SurfaceHolder surfaceHolder;
	private Random rand;
	private int mScreenWidth, mScreenHeight;
	private int heartCenterX, heartCenterY;
	private float scaleFactor;
	private boolean isAlive;

	private Bitmap happyBirthdayText; // 生日快乐文字图片
	private boolean isTextScaled;
	private Bitmap[] candleBitmaps; // 蜡烛图片，用于绘制晃动的烛光
	private boolean[] isCandleScaled;
	private Bitmap[] cartonBitmaps; // carton图片
	private boolean[] isCartonPicScaled;
	private int curCartonPicIndex;

	private int[][] heartPoints; // 组成心形的点的坐标
	private CandleDrawingInfo[] drawingCandles; // 组成心形的蜡烛
	private ArrayList<Integer> notLitCandleNum; // 还未被点亮的蜡烛编号

	private MediaPlayer happyBirthdaySong, thePianoOfNight; // 生日快乐歌 + 夜的进行曲
	private boolean isSongPlayed;
	private int sonePlayedTimes;
	private static final int MAX_PLAY_TIMES = 1;

	private String hintMessage; // 提示信息
	private Paint hintPaint;

	private Bitmap cakeBitmap, cakePlateBitmap; // 蛋糕+盘子
	private boolean isCakeScaled, isCakePlateScaled;
	private Paint cakePaint;

	private boolean isAllCandleLit;
	private boolean isAllCandleBlownOut;
	private boolean isToStartEatCake;

	// 碰触事件
	private float mX, mY; // point of end or moving
	private long startTime;
	private Path mPath;
	// 模拟风效果
	private Path[] windPaths;
	private PathEffect[] windEffects;
	private Paint mWindPaint;
	GestureDetector mGestureDetector;
	private ArrayList<Point> windRunLocs;
	// 模拟吃蛋糕事件
	private Canvas eatCakeCanvas;
	private Paint eatCakePaint;
	private float eatenProportion;
	private static final float TOUCH_TOLERANCE = 32;

	private boolean toWatchCandleDance;

	private static final int COLOR_HINT_1 = Color.rgb(0xFF, 0x69, 0xB4);
	private static final int COLOR_HINT_2 = Color.BLUE;
	private static final int COLOR_HINT_3 = Color.GREEN;
	private static final int COLOR_HINT_4 = 0xFFFA8072;
	private static final int COLOR_WIND = Color.rgb(0xD2, 0xB4, 0x8C);

	public HappyBirthdayView(Context context) {
		super(context);
		surfaceHolder = this.getHolder();
		surfaceHolder.addCallback(this);
		this.setFocusable(true);
		rand = new Random();

		hintMessage = "";
		hintPaint = new Paint();
		hintPaint.setColor(COLOR_HINT_1);
		Typeface font = Typeface.createFromAsset(getResources().getAssets(), "font/shao_nv_ti.ttf");
		hintPaint.setTypeface(font);
		hintPaint.setTextSize(36);

		// 初始化蜡烛烛光png资源
		Log.i("lew.scott.out", "初始化happyBirthdayText图片");
		try {
			InputStream is = context.getResources().openRawResource(R.drawable.happy_birthday);
			happyBirthdayText = BitmapFactory.decodeStream(is);
		} catch (Exception e) {
			Log.e("lew.scott.out", "Error in 初始化happyBirthdayText图片");
		}

		// 初始化蜡烛烛光png资源
		Log.i("lew.scott.out", "初始化蜡烛烛光png资源");
		try {
			final String CANDLE_PATH = "candle";
			final int COUNT = 10;
			candleBitmaps = new Bitmap[COUNT];
			isCandleScaled = new boolean[COUNT];
			for (int i = 0; i < COUNT; i++) {
				InputStream is = getResources().getAssets().open(CANDLE_PATH + '/' + (i + 1) + ".png");
				candleBitmaps[i] = BitmapFactory.decodeStream(is);
			}
		} catch (Exception e) {
			Log.e("lew.scott.out", "Error in 初始化蜡烛烛光png资源");
		}

		// 初始化carton图片
		Log.i("lew.scott.out", "初始化carton图片");
		try {
			final String CARTON_PATH = "carton";
			final int COUNT = 2;
			cartonBitmaps = new Bitmap[COUNT];
			isCartonPicScaled = new boolean[COUNT];
			for (int i = 0; i < COUNT; i++) {
				InputStream is = getResources().getAssets().open(CARTON_PATH + '/' + (i + 1) + ".png");
				cartonBitmaps[i] = BitmapFactory.decodeStream(is);
			}
		} catch (Exception e) {
			Log.e("lew.scott.out", "Error in 初始化carton图片");
		}

		// 初始化心形点坐标
		Log.i("lew.scott.out", "初始化心形点坐标");
		heartPoints = new int[][]{ // 由22个点组成，300px*250px大小，心窝为(0,0)
		{0, 0}, {34, -21}, {69, -39}, {106, -45}, {131, -17}, {135, 16}, {122, 49}, {107, 76}, {86, 108},
				{60, 138}, {34, 163},
				{0, 182}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}
		};
		for (int i = 1; i < 11; i++) { // 对称赋值
			heartPoints[i + 11][0] = -heartPoints[i][0];
			heartPoints[i + 11][1] = heartPoints[i][1];
		}

		// 初始化蜡烛
		Log.i("lew.scott.out", "初始化蜡烛");
		drawingCandles = new CandleDrawingInfo[heartPoints.length];
		for (int i = 0; i < drawingCandles.length; i++) {
			drawingCandles[i] = new CandleDrawingInfo();
		}

		// 初始化还未被点亮的蜡烛编号
		Log.i("lew.scott.out", "初始化还未被点亮的蜡烛编号");
		notLitCandleNum = new ArrayList<Integer>(heartPoints.length);
		for (int i = 0; i < heartPoints.length; i++) {
			notLitCandleNum.add(Integer.valueOf(i));
		}
		Collections.shuffle(notLitCandleNum);// 打乱蜡烛编号
		Log.d("lew.scott.out", "初始化还未被点亮的蜡烛编号:" + notLitCandleNum.toString());

		// 初始化happyBirthdaySong
		happyBirthdaySong = MediaPlayer.create(context, R.raw.happy_birthday_song);
		// happyBirthdaySong.setLooping(true);
		happyBirthdaySong.setOnCompletionListener(new OnCompletionListener() {
			public void onCompletion(MediaPlayer mp) {
				Log.i("lew.scott.out", "生日快乐歌唱了一遍");
				sonePlayedTimes++;
				if (sonePlayedTimes >= MAX_PLAY_TIMES) {
					// 开始吃蛋糕
					isToStartEatCake = true;
					disturbCandleLightStep(); // 乱序烛光晃动步调
				} else {
					// 再唱一遍
					try {
						happyBirthdaySong.start();
					} catch (Exception e) {
						Log.e("lew.scott.out", "Error to play happyBirthdaySong");
					}
				}
			}
		});
		thePianoOfNight = MediaPlayer.create(context, R.raw.the_piano_of_night);
		thePianoOfNight.setLooping(true);

		// 初始化蛋糕和盘子
		try {
			InputStream is = context.getResources().openRawResource(R.drawable.cake);
			cakeBitmap = BitmapFactory.decodeStream(is);
			is = context.getResources().openRawResource(R.drawable.cake_plate);
			cakePlateBitmap = BitmapFactory.decodeStream(is);
		} catch (Exception e) {
			Log.e("lew.scott.out", "Error in 初始化蛋糕和盘子");
		}
		cakePaint = new Paint();
		ColorMatrix cMatrix = new ColorMatrix();
		cMatrix.setScale(0.01f, 0.01f, 0.01f, 1);
		cakePaint.setColorFilter(new ColorMatrixColorFilter(cMatrix));

		// 初始化碰触事件元素
		mPath = new Path();
		mWindPaint = new Paint();
		mWindPaint.setColor(COLOR_WIND);
		mWindPaint.setStyle(Paint.Style.STROKE);
		mWindPaint.setStrokeJoin(Paint.Join.ROUND);
		mWindPaint.setStrokeCap(Paint.Cap.ROUND);
		mWindPaint.setStrokeWidth(1);
		PathEffect[] e = windEffects = new PathEffect[12]; // 模拟风的效果
		for (int i = 0; i < e.length; i++) {
			e[i] = new DashPathEffect(new float[]{20, 10, 15, 7}, i * 15);
		}
		Path[] p = windPaths = new Path[e.length];
		for (int i = 0; i < p.length; i++) {
			p[i] = new Path();
		}
		mGestureDetector = new GestureDetector(this);
		windRunLocs = new ArrayList<Point>(32); // 用于保存风吹过的点
		eatCakeCanvas = new Canvas();
		eatCakePaint = new Paint();
		eatCakePaint.setAlpha(0);
		eatCakePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
		eatCakePaint.setAntiAlias(true);
		eatCakePaint.setDither(true);
		eatCakePaint.setStyle(Paint.Style.STROKE);
		eatCakePaint.setStrokeJoin(Paint.Join.BEVEL);
		eatCakePaint.setStrokeCap(Paint.Cap.ROUND);
		eatCakePaint.setStrokeWidth(60);
	}
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		mScreenWidth = holder.getSurfaceFrame().width();
		mScreenHeight = holder.getSurfaceFrame().height();
		// 初始化蜡烛坐标
		Log.i("lew.scott.out", "初始化蜡烛坐标");
		int centerPointX = mScreenWidth / 2;
		int centerPointY = mScreenHeight / 2;
		Log.d("lew.scott.out", "centerPointX: " + centerPointX);
		Log.d("lew.scott.out", "centerPointY: " + centerPointY);
		// 一定比例的伸缩，和微调，烛光大小为29*30
		float factor = (float) centerPointX / 170;
		float factor2 = (float) centerPointY / 220;
		if (factor > factor2) {
			factor = factor2;
		}
		heartCenterX = centerPointX;
		heartCenterY = centerPointY - 125;
		scaleFactor = factor;
		Log.d("lew.scott.out", "scaleFactor: " + scaleFactor);
		for (int i = 0; i < drawingCandles.length; i++) {
			drawingCandles[i].x = (int) ((heartPoints[i][0] - 15) * factor) + heartCenterX;
			drawingCandles[i].y = (int) ((heartPoints[i][1] - 15) * factor) + heartCenterY;
		}

		// 启动动画线程
		isAlive = true;
		new MainAnimationThread().start();
		// 播放夜的钢琴曲
		try {
			thePianoOfNight.prepare();
		} catch (Exception e) {
			Log.e("lew.scott.out", "Error to prepare thePianoOfNight");
			e.printStackTrace();
		}
		try {
			thePianoOfNight.start();
		} catch (Exception e) {
			Log.e("lew.scott.out", "Error to play thePianoOfNight");
			e.printStackTrace();
		}
		if (isSongPlayed && (sonePlayedTimes < MAX_PLAY_TIMES)) {
			// 播放生日快乐歌
			try {
				happyBirthdaySong.prepare();
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error to prepare happyBirthdaySong");
				e.printStackTrace();
			}
			try {
				happyBirthdaySong.start();
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error to play happyBirthdaySong");
				e.printStackTrace();
			}
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		Log.i("lew.scott.out", "HappyBirthdayView.surfaceChanged()");

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		isAlive = false;
		if (happyBirthdaySong != null && happyBirthdaySong.isPlaying()) {
			try {
				happyBirthdaySong.pause();
				// happyBirthdaySong.release();
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error to pause happyBirthdaySong");
				e.printStackTrace();
			}
		}
		if (thePianoOfNight != null && thePianoOfNight.isPlaying()) {
			try {
				thePianoOfNight.pause();
				// thePianoOfNight.release();
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error to pause thePianoOfNight");
				e.printStackTrace();
			}
		}
	}

	/**
	 * 点亮一个蜡烛
	 */
	private void litOneCandle() {
		if (isAllCandleLit) {
			return;
		}
		int size = notLitCandleNum.size();
		if (size > 0) {
			Integer num = notLitCandleNum.remove(--size);
			CandleDrawingInfo curCandle = drawingCandles[num];
			curCandle.isLit = true;
			Log.i("lew.scott.out", "点亮一个蜡烛：" + num + "(" + curCandle.x + "," + curCandle.y + ")");
			// 调节蛋糕亮度
			float brightness = (float) (drawingCandles.length - size) / (drawingCandles.length + 4);
			// brightness *= brightness; // 二次方
			ColorMatrix cMatrix = new ColorMatrix();
			cMatrix.setScale(brightness, brightness, brightness, 1);
			cakePaint.setColorFilter(new ColorMatrixColorFilter(cMatrix));
		} else {
			isAllCandleLit = true;
			cakePaint.setColorFilter(null);
		}
	}

	/**
	 * 绘制蜡烛
	 */
	private void drawCandles(Canvas canvas, int frameCounter) {
		for (CandleDrawingInfo curCandle : drawingCandles) {
			if (!curCandle.isLit || candleBitmaps == null || candleBitmaps.length == 0) {
				continue;
			}
			if (curCandle.curIndex >= candleBitmaps.length || curCandle.curIndex < 0) {
				curCandle.curIndex = 0;
			}
			int i = curCandle.curIndex;
			Bitmap bitmap = candleBitmaps[i];
			if (bitmap != null) {
				if (!isCandleScaled[i]) {
					Matrix m = new Matrix();
					m.setScale(scaleFactor, scaleFactor);
					Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
							bitmap.getHeight(), m, true);
					bitmap = candleBitmaps[i] = tmp;
					isCandleScaled[i] = true;
				}
				canvas.drawBitmap(bitmap, curCandle.x, curCandle.y, null);
			}
			if ((frameCounter + 1) % (MainAnimationThread.FRAMES_PER_SECOND / 7) == 0) { // 每秒7帧
				curCandle.curIndex++; // 烛光下一帧
			}
		}
	}

	// 同步烛光晃动步调
	private void accordCandleLightStep() {
		for (CandleDrawingInfo curCandle : drawingCandles) {
			curCandle.curIndex = 0;
		}
	}

	// 乱序烛光晃动步调
	private void disturbCandleLightStep() {
		for (CandleDrawingInfo curCandle : drawingCandles) {
			curCandle.curIndex = rand.nextInt(candleBitmaps.length);
		}
	}

	/**
	 * 绘制蛋糕
	 */
	private void drawCake(Canvas canvas) {
		// 先绘制盘子
		Bitmap bitmap = cakePlateBitmap;
		if (!isCakePlateScaled) {
			Matrix m = new Matrix();
			m.setScale(scaleFactor, scaleFactor);
			Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
						bitmap.getHeight(), m, true);
			bitmap = cakePlateBitmap = tmp;
			isCakePlateScaled = true;
		}
		canvas.drawBitmap(bitmap, heartCenterX - bitmap.getWidth() / 2,
					heartCenterY - (scaleFactor * 75), cakePaint);
		// 绘制蛋糕
		if (eatenProportion == 1) {
			return; // 吃完了就不再绘制蛋糕了
		}
		bitmap = cakeBitmap;
		if (!isCakeScaled) {
			Matrix m = new Matrix();
			m.setScale(scaleFactor, scaleFactor);
			Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
						bitmap.getHeight(), m, true);
			bitmap = cakeBitmap = tmp;
			isCakeScaled = true;
			eatCakeCanvas.setBitmap(bitmap);
		}
		canvas.drawBitmap(bitmap, heartCenterX - bitmap.getWidth() / 2,
					heartCenterY - (scaleFactor * 75), cakePaint);
	}

	/**
	 * 绘制生日快乐文字图片
	 */
	private void drawHappyBirthdayText(Canvas canvas) {
		if (isAllCandleLit && !isAllCandleBlownOut) {
			Bitmap bitmap = happyBirthdayText;
			if (!isTextScaled) {
				Matrix m = new Matrix();
				m.setScale(scaleFactor, scaleFactor);
				Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
						bitmap.getHeight(), m, true);
				bitmap = happyBirthdayText = tmp;
				isTextScaled = true;
			}
			canvas.drawBitmap(bitmap, heartCenterX - bitmap.getWidth() / 2,
					heartCenterY + bitmap.getHeight() / 2, null);
		}
	}

	/**
	 * 绘制提示信息
	 */
	private void drawHintMessage(Canvas canvas) {
		if (!isAllCandleLit) {
			return;
		}
		if (toWatchCandleDance) {
			// 由CandleDanceThread控制
		} else if (isToStartEatCake) {
			if (isAllCandleBlownOut) {
				if (eatenProportion == 1) {
					hintMessage = "吃完了，\n没有了,\n以后再吃(⊙o⊙)";
					toWatchCandleDance = true;
					new CandleDanceThread().start();
				} else if (eatenProportion > 0.8 && eatenProportion < 1) {
					hintMessage = "还剩点儿渣渣，\n不能浪费\n舔干净(⊙﹏⊙)";
				} else {
					hintMessage = "吃蛋糕吧，\n直接下手就可以了(∩_∩)\n不要吃盘子!@!";
				}
				hintPaint.setColor(COLOR_HINT_3);
			} else {
				hintMessage = "看看你几下，\n能吹灭所有的蜡烛\n不过这里需要用“手”吹~~";
				hintPaint.setColor(COLOR_HINT_2);
			}
		} else {
			hintMessage = "小敏敏：\n生日快乐！\n许个愿吧^.^";
		}
		this.myDrawText(canvas, hintMessage, 15, mScreenHeight - 120, hintPaint);
	}

	private void myDrawText(Canvas canvas, String msg, int x, int y, Paint paint) {
		if (paint == null) {
			return;
		}
		FontMetrics fm = paint.getFontMetrics();// 得到系统默认字体属性
		int fontHeight = (int) (Math.ceil(fm.descent - fm.top) + 2);// 获得字体高度
		// Log.d("lew.scott.out", "in myDrawText()fontHeight=" + fontHeight);
		if (fontHeight <= 4) {
			fontHeight = (int) paint.getTextSize();
		}
		String[] strs = msg.split("\n");
		for (int i = 0; i < strs.length; i++) {
			canvas.drawText(strs[i], x, y, paint);
			y += fontHeight;
		}
	}

	/**
	 * 绘制carton图片
	 */
	private void drawCartonPics(Canvas canvas, int counter) {
		if (isAllCandleLit && !isToStartEatCake) {
			if (curCartonPicIndex >= cartonBitmaps.length) {
				curCartonPicIndex = 0;
			}
			int i = curCartonPicIndex;
			Bitmap bitmap = cartonBitmaps[i];
			if (bitmap != null) {
				if (!isCartonPicScaled[i]) {
					Matrix m = new Matrix();
					m.setScale(scaleFactor, scaleFactor * 0.8f);
					Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
							bitmap.getHeight(), m, true);
					bitmap = cartonBitmaps[i] = tmp;
					isCartonPicScaled[i] = true;
				}
				canvas.drawBitmap(bitmap, (mScreenWidth - bitmap.getWidth()) / 2, 5, null);
			}
			if ((counter + 1) % (MainAnimationThread.FRAMES_PER_SECOND / 2) == 0) { // 每秒2帧
				curCartonPicIndex++;
			}
		}
	}

	/**
	 * 播放生日快乐歌
	 */
	private void toPlayHappyBirthdaySong() {
		if (!isSongPlayed && isAllCandleLit) {
			try {
				happyBirthdaySong.prepare();
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error to prepare happyBirthdaySong");
				e.printStackTrace();
			}
			try {
				happyBirthdaySong.start();
				thePianoOfNight.setVolume(0.5f, 0.5f);
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error to play happyBirthdaySong");
				e.printStackTrace();
			}
			isSongPlayed = true;
			// 同步烛光晃动步调
			accordCandleLightStep();
		}
	}

	class CandleDanceThread extends Thread {
		@Override
		public void run() {
			try {
				sleep(2000);
				hintPaint.setColor(COLOR_HINT_4);
				hintMessage = "下面欣赏一段《烛光舞》吧";
				sleep(1000);
				// 第一乐章 - 心
				drawingCandles[0].isLit = true;
				drawingCandles[0].curIndex = 0;
				sleep(1000);
				for (int i = 1; i <= 10; i++) {
					drawingCandles[i].isLit = true;
					drawingCandles[i].curIndex = drawingCandles[0].curIndex;
					drawingCandles[i + 11].isLit = true;
					drawingCandles[i + 11].curIndex = drawingCandles[0].curIndex;
					sleep(1000);
				}
				drawingCandles[11].isLit = true;
				drawingCandles[11].curIndex = drawingCandles[0].curIndex;
				sleep(2000);
				drawingCandles[0].isLit = false;
				sleep(1000);
				for (int i = 1; i <= 10; i++) {
					drawingCandles[i].isLit = false;
					drawingCandles[i + 11].isLit = false;
					sleep(1000);
				}
				drawingCandles[11].isLit = false;
				sleep(2000);
				// 第2乐章 - 圆
				final float R = scaleFactor * 120;
				final double THETA = 2 * Math.PI / drawingCandles.length;
				final int X_DIFF = heartCenterX - (int) (18 * scaleFactor);
				final int Y_DIFF = heartCenterY - (int) (scaleFactor * 75) + cakePlateBitmap.getHeight() / 2
						- (int) (scaleFactor * 20);
				for (int i = 0; i < drawingCandles.length; i++) {
					double rad = 3 * Math.PI / 2 + i * THETA;
					drawingCandles[i].x = (int) (R * Math.cos(rad)) + X_DIFF;
					drawingCandles[i].y = (int) (R * Math.sin(rad)) + Y_DIFF;
					if (i == 0) {
						drawingCandles[i].curIndex = 0;
					} else {
						drawingCandles[i].curIndex = drawingCandles[i - 1].curIndex + 1;
					}
					drawingCandles[i].isLit = true;
					sleep(1000);
				}
				sleep(3000);
				accordCandleLightStep();
				sleep(3000);
				// 转圈
				int speed = 5; // 速度：步数/每秒
				int inc = 0;
				while (speed < 100) {
					int step = 0;
					while (step < speed * 3) { // 每次3s
						double delta = 3 * Math.PI / 2 + (inc++) * Math.PI / 60;
						for (int i = 0; i < drawingCandles.length; i++) {
							double rad = i * THETA + delta;
							drawingCandles[i].x = (int) (R * Math.cos(rad)) + X_DIFF;
							drawingCandles[i].y = (int) (R * Math.sin(rad)) + Y_DIFF;
						}
						sleep(1000 / speed);
						step++;
					}
					speed += 5;
				}
				sleep(5000);
				disturbCandleLightStep();
				sleep(3000);
				for (int i = 0; i < drawingCandles.length; i++) {
					drawingCandles[i].isLit = false;
					sleep(1000);
				}
				hintMessage = "That's ALL.\nThank you!";
				sleep(3000);
				hintMessage = "哈哈！\n生日快乐！";
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error in CandleDanceThread()");
				e.printStackTrace();
			}
		}
	}

	/**
	 * 动画主线程
	 */
	class MainAnimationThread extends Thread {

		static final int INTERVAL_MS = 40; // 预计一秒25帧
		static final int FRAMES_PER_SECOND = 1000 / INTERVAL_MS;
		static final int CANDLE_FRAMES = 20; // 每隔多少帧，点燃一个蜡烛
		private int counter = 0;
		private int frameCounter = 0;
		private boolean isAllCandleDrawed; // 所有蜡烛被点燃，不表示所有蜡烛绘制完成

		private void mainDrawing(Canvas canvas) {
			// Log.v("lew.scott.out", "mainDrawing, i=" + frameCounter);
			canvas.drawColor(Color.BLACK, Mode.CLEAR); // 清空

			drawCake(canvas); // 绘制蛋糕

			drawCandles(canvas, frameCounter); // 绘制蜡烛

			if (isAllCandleDrawed) {
				drawHappyBirthdayText(canvas); // 绘制生日快乐文字图片

				drawHintMessage(canvas); // 绘制提示信息

				drawCartonPics(canvas, frameCounter); // 绘制carton图片

				toPlayHappyBirthdaySong(); // 播放生日快乐歌
			} else {
				if (isAllCandleLit && counter == CANDLE_FRAMES - 1) {
					// 当所有蜡烛被点亮后，再等一轮再绘制生日文字和其他
					isAllCandleDrawed = true;
				}
			}

			counter++;
			if (counter == CANDLE_FRAMES) { // 每隔一定时间点亮一个蜡烛
				litOneCandle();
				counter = 0;
			}
			frameCounter++;
			if (frameCounter == FRAMES_PER_SECOND) {
				frameCounter = 0;
			}
		}

		@Override
		public void run() {
			try {
				while (isAlive) {
					Canvas canvas = surfaceHolder.lockCanvas();
					mainDrawing(canvas);
					surfaceHolder.unlockCanvasAndPost(canvas);
					sleep(INTERVAL_MS);
				}
			} catch (Exception e) {
				Log.e("lew.scott.out", "Error in MainAnimationThread.run()");
				e.printStackTrace();
			}
		}

	}

	/**
	 * 碰触事件
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// return mGestureDetector.onTouchEvent(event);
		if (!isToStartEatCake) {
			return true;
		}

		float x = event.getX();
		float y = event.getY();

		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN :
				// Log.d("lew.scott.out", "MotionEvent (" + x + "," + y + ") start");
				touch_start(x, y);
				break;
			case MotionEvent.ACTION_MOVE :
				// Log.d("lew.scott.out", "MotionEvent (" + x + "," + y + ") move");
				touch_move(x, y);
				break;
			case MotionEvent.ACTION_UP :
				// Log.d("lew.scott.out", "MotionEvent (" + x + "," + y + ") up");
				touch_up(x, y);
				break;
		}
		return true;
	}

	private void touch_start(float x, float y) {
		startTime = System.currentTimeMillis();
		mX = x;
		mY = y;
		mPath.reset();
		mPath.moveTo(x, y);
		windRunLocs.clear();
	}
	private void touch_move(float x, float y) {
		float dx = Math.abs(x - mX);
		float dy = Math.abs(y - mY);
		if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
			float midX = (x + mX) / 2, midY = (y + mY) / 2;
			// mPath.lineTo(midX, midY);
			mPath.quadTo(mX, mY, midX, midY);
			windRunLocs.add(new Point((int) midX, (int) midY));
			mX = x;
			mY = y;
			// drawTouchPath(0);
		}
	}
	private void touch_up(float x, float y) {
		mPath.lineTo(x, y);
		windRunLocs.add(new Point((int) x, (int) y));
		if (!isAllCandleBlownOut) {
			long endTime = System.currentTimeMillis();
			long interval = endTime - startTime;
			int len = windEffects.length;
			// 根据时间间隔计算强度
			int strength = len - (int) (interval * len / 720);
			if (strength < 0) {
				strength = 0;
			}
			// 绘制风
			drawWindPath(strength);

			// 熄灭被吹到的蜡烛
			blowOutCandle(strength);
		} else {
			if (eatenProportion < 1) {
				// 需要偏移(0,0)减去(蛋糕bitmap的位置)
				mPath.offset(-(heartCenterX - cakeBitmap.getWidth() / 2),
						-(heartCenterY - (scaleFactor * 75)));
				eatCakeCanvas.drawPath(mPath, eatCakePaint);
				// 计算cakeBitmap被擦除的比例
				int w = cakeBitmap.getWidth(), h = cakeBitmap.getHeight();
				int alphaCount = 0, totalCount = w * h;
				int[] pixels = new int[totalCount];
				cakeBitmap.getPixels(pixels, 0, w, 0, 0, w, h);
				for (int clr : pixels) {
					if ((clr & 0xFF000000) == 0) {
						alphaCount++;
					}
				}
				eatenProportion = (float) alphaCount / totalCount;
				Log.d("lew.scott.out", "alphaCount=" + alphaCount);
				Log.d("lew.scott.out", "totalCount=" + totalCount + "(" + w + "*" + h + ")");
				Log.d("lew.scott.out", "proportion=" + eatenProportion);
				if (eatenProportion > 0.98) { // 直接清空
					eatCakeCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
				}
			}
		}

		mPath.reset();
		windRunLocs.clear();
	}

	private void drawWindPath(int strength) {
		int len = windEffects.length;
		int s2 = strength << 1; // 偏移范围
		// 开始绘制
		Canvas canvas = surfaceHolder.lockCanvas();
		mWindPaint.setPathEffect(windEffects[rand.nextInt(len)]);
		canvas.drawPath(mPath, mWindPaint);
		for (int i = 0; i < strength; i++) {
			mPath.offset(rand.nextInt(s2) - strength, rand.nextInt(s2) - strength, windPaths[i]);
			mWindPaint.setPathEffect(windEffects[rand.nextInt(len)]);
			canvas.drawPath(windPaths[i], mWindPaint);
		}
		surfaceHolder.unlockCanvasAndPost(canvas);
	}

	private void blowOutCandle(int strength) {
		Log.i("lew.scott.out", "strength=" + strength);
		Log.i("lew.scott.out", "windRunLocs=" + windRunLocs.toString());
		if (strength < 4) {
			return;
		}
		isAllCandleBlownOut = true;
		final float DIFF_ALLOWANCE = TOUCH_TOLERANCE * TOUCH_TOLERANCE * scaleFactor * scaleFactor;
		for (CandleDrawingInfo curCandle : drawingCandles) {
			// 获取灯芯坐标，烛光大小为29*30
			int cX = curCandle.x + (int) (scaleFactor * 15), cY = curCandle.y + (int) (scaleFactor * 15);
			for (Point p : windRunLocs) {
				float dx = cX - p.x, dy = cY - p.y;
				float distance = dx * dx + dy * dy;
				if (distance < DIFF_ALLOWANCE) {
					curCandle.isLit = false;
				}
			}
			isAllCandleBlownOut = isAllCandleBlownOut && (!curCandle.isLit);
		}
	}

	@Override
	public boolean onDown(MotionEvent e) {
		return false;
	}
	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		Log.i("lew.scott.out", "MotionEvent onFling");
		return false;
	}
	@Override
	public void onLongPress(MotionEvent e) {
		Log.i("lew.scott.out", "MotionEvent onLongPress");
	}
	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
		Log.i("lew.scott.out", "MotionEvent onScroll");
		return false;
	}
	@Override
	public void onShowPress(MotionEvent e) {
	}
	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		Log.i("lew.scott.out", "MotionEvent onSingleTapUp");
		return false;
	}
}
